#pragma once

/*
 * mysql module
 */

#include <map>
#include "mysql_db.h"
#include "mysql_connection.h"
#include "gnthrdqueue.h"
#include "dynamicpool.h"
#include "mysql_recordset.h"
#include <vector>
#include <list>
#include "gnmutex.h"

namespace SMysqlSpace {
	class CMysqlModule : public IMysqlModule {
	public:
		static bool CreateInstance() {
			if (nullptr == m_poInstance) {
				m_poInstance = new CMysqlModule();
				return nullptr != m_poInstance;
			}
			return true;
		}

		static CMysqlModule* Instance() {
			CreateInstance();
			return m_poInstance;
		}

		static void DestroyInstance() {
			if (m_poInstance != nullptr) {
				delete m_poInstance;
				m_poInstance = nullptr;
			}
		}

	protected:
		CMysqlModule();
		virtual ~CMysqlModule();
		CMysqlModule(const CMysqlModule& rhs) = delete;
		CMysqlModule& operator=(const CMysqlModule& rhs) = delete;

		typedef CDynamicPoolEx<CMysqlRecordset, CLocker> CRecordsetPool;
		typedef std::vector<CMysqlConnection*> CConnectVec;
		typedef std::map<int, CConnectVec> group2ConnectionMap;
		enum eConst { initSize = 4, growSize = 2 };

	public:
		// busy return true, else return false;
		virtual bool STDCALL Run(int count = -1);

		// connection
		// paras: group, connect num: connect: 0, 1, 2, ...
		virtual bool STDCALL Connect(int group, const SConnectMysqlInfo& connectInfo, int connNum = 1);

		// find connection
		virtual IMysqlConnection* STDCALL FindConnection(int group, int index);

		// add command
		virtual bool STDCALL AddCommand(int group, int index, ICommand* poCommand, bool bHighPriority = false);

		// escape string to mysql.
		virtual int STDCALL EscapeString(int group, const char* from, int fromLen, char* to, int toLen);
		virtual int STDCALL EscapeString(const char* from, int fromLen, char* to, int toLen);

		// direct SQL operation
		virtual int STDCALL QueryWithoutResult(int group, int index, const char* sql);
		virtual int STDCALL QueryWithResult(int group, int index, const char* sql, IMysqlRecordset** ppRes);

		// query last error
		virtual const char* STDCALL GetLastError(int group, int index);
		virtual int STDCALL GetLastErrorNo(int group, int index);

		// release
		virtual void STDCALL Release();

		// close.
		virtual bool STDCALL Close(int group);

	public:
		// init
		bool Init();

		// reference function
		void AddRef() { m_ref++; }
		void DecRef() { m_ref--; }

		// record set pool method
		CMysqlRecordset* CreateRecordset() {
			return m_recordsetPool.FetchObj();
		}
		void ReleaseRecordset(CMysqlRecordset* poRSet) {
			m_recordsetPool.ReleaseObj(poRSet);
		}

	protected:
		friend class CMysqlConnection;
		void AddExecutedCommand(ICommand* poCommand);

	private:
		static CMysqlModule* m_poInstance;
		int  m_ref{ 0 };

		// connect lists
		group2ConnectionMap m_group2Connection;

		// finished command list
		CLocker  m_locker;
		std::list<ICommand*> m_listCommand;

		// record set pool
		CRecordsetPool  m_recordsetPool;
	};
}